using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using NetProtocol.Enum;
using System;

namespace IQIGame.Onigao.Logic
{
    public static class LgLevelEntityExtension
    {
        public static bool HasTriggerRect(this LevelEntity entity)
        {
            return entity.triggerRect.Width > 0 && entity.triggerRect.Height > 0;
        }

        public static Vector2Logic GetPosition2D(this LevelEntity entity)
        {
            return new Vector2Logic(entity.position.x, entity.position.z);
        }

        public static FixedBVHBounds2D GetBvhBounds(this LevelEntity entity)
        {
            if (!entity.HasTriggerRect())
            {
                LogicLog.LogError("该实体没有TriggerRect");
                return default;
            }
            RectInt rect = entity.triggerRect;
            Vector2Logic pos = new Vector2Logic(entity.position.x + rect.X, entity.position.z + rect.Y);
            Vector2Logic size = new Vector2Logic(rect.Width, rect.Height);
            FixedBVHBounds2D bvhBounds;
            if (entity.isTriggerRectRotated)
            {
                Vector3Logic euler = Vector3Logic.DirectionToEulerXy(entity.dir);
                //获取旋转后的包围盒矩形的最小外包围矩形
                //依然是不带旋转的矩形
                bvhBounds = FixedBVHBounds2D.FromPosSizeRotationY(pos, size, euler.y);
            }
            else
            {
                bvhBounds = FixedBVHBounds2D.FromPosSize(pos, size);
            }
            return bvhBounds;
        }

        public static void SetRotationY(this LevelHeroEntity entity, int rotationY)
        {
            Vector3Logic euler = Vector3Logic.DirectionToEulerXy(entity.dir);
            euler.y = rotationY;
            entity.dirUnnormalized = Vector3Logic.EulerXyToDirection(euler, false);
            entity.region.UpdateEntityRotationY(null, entity, LevelEntityType.Hero, (int)euler.y);
        }

        public static void SetRotationY(this LevelEntity entity, int rotationY, bool syncToClient)
        {
            Vector3Logic euler = Vector3Logic.DirectionToEulerXy(entity.dir);
            euler.y = rotationY;
            entity.UpdateRotation(euler, syncToClient);
        }

        public static void SetRotationY(this LevelEntity entity, int rotationY, bool isIncrement, bool syncToClient)
        {
            Vector3Logic euler = Vector3Logic.DirectionToEulerXy(entity.dir);
            if (isIncrement)
            {
                euler.y = (euler.y + rotationY + 360) % 360;
            }
            else
            {
                euler.y = rotationY;
            }
            entity.UpdateRotation(euler, syncToClient);
        }

        /// <summary>
        /// 检查某个坐标是否被包含在实体碰撞盒之内
        /// </summary>
        /// <param name="entity1"></param>
        /// <param name="entity2"></param>
        /// <returns></returns>
        public static bool IsContains(this LevelEntity entity, Vector3Logic position)
        {
            FixedOBBRect entityRect = entity.GetEntityOBBRect();
            return entityRect.Contains(new Vector2Logic(position.x, position.z));
        }

        public static FixedOBBRect GetEntityOBBRect(this LevelEntity entity)
        {
            var offset = new Vector3Logic(entity.triggerRect.X, 0, entity.triggerRect.Y);
            float rotationY = 0;
            if (entity.isTriggerRectRotated)
            {
                Vector3Logic euler = Vector3Logic.DirectionToEulerXy(entity.dir);
                rotationY = euler.y;
                offset = QuaternionLogic.Euler(euler) * offset;
            }
            return new FixedOBBRect(entity.position + offset, entity.triggerRectBoxSize, rotationY);
        }

        /// <summary>
        /// 目标位置是否在entity的triggerRect高度范围以内
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        public static bool IsInTriggerRectHeightRange(this LevelEntity entity, Vector3Logic position)
        {
            return entity.triggerRectHalfHeight == 0 || Math.Abs(position.y - entity.position.y) <= entity.triggerRectHalfHeight;
        }

        /// <summary>
        /// 电梯楼层激活状态
        /// </summary>
        public static bool[] GetElevatorFloorActivation(this LevelEntity entity)
        {
            EntityPropElevator prop = entity.GetDynamicProperty(EntityDynamicPropertyType.Elevator) as EntityPropElevator;
            if (prop == null)
            {
                return null;
            }
            return prop.floorActiveList;
        }

        /// <summary>
        /// 获取电梯当前停靠的楼层
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static int CalcElevatorFloor(this LevelEntity entity)
        {
            EntityParamElevator elevatorParam = entity.GetDynamicParam(EntityDynamicParamType.Elevator) as EntityParamElevator;
            if (elevatorParam == null)
            {
                LogicLog.LogError($"实体[{entity.entityConfig?.id}]不是电梯。");
                return -1;
            }
            if (entity.region.IsRunningElevator(entity.id))
            {
                LogicLog.LogError($"电梯(entity id: {entity.entityConfig?.id})正在运行，无法计算停靠楼层。");
                return -1;
            }
            int minDis = int.MaxValue;
            int curFloor = 0;
            for (int i = 0; i < elevatorParam.floors.Count; i++)
            {
                Framework.Vector3Int entityPos = entity.position;
                ElevatorFloorData floorData = elevatorParam.floors[i];
                int sqrDis = (floorData.position - entityPos).sqrMagnitude;
                if (sqrDis < minDis)
                {
                    minDis = sqrDis;
                    curFloor = i;
                }

            }
            return curFloor;
        }

        public static int GetInteractMinDistance(this LevelEntity entity)
        {
            ObstacleInfo obstacle = entity.entityConfig.obstacle;
            if (obstacle != null && !obstacle.invalid)
            {
                return obstacle.maxDisToCenter + LgLevelConst.HeroEntityRadius + LgLevelConst.InteractMaxBoundsGap;
            }
            return LgLevelConst.DefaultInteractRange;
        }

        public static bool IsOfferingQuest(this LevelEntity entity, LevelPlayer player)
        {
            var paramQuest = entity.GetDynamicParam(EntityDynamicParamType.QuestList) as EntityParamQuest;
            if (paramQuest != null)
            {
                var quests = paramQuest.offerQuests;
                foreach (int cid in quests)
                {
                    if (LogicQuestModule.Instance.IsAcceptable(player.logicPlayer, cid, entity))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}
